package cn.always.xiajia.framework.common.util;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;

import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;

/**
 * 对象属性赋值工具类
 *
 **/
public class ExtBeanCopyUtils {
	
	private ExtBeanCopyUtils() {
		
	}

	/**
	 * 如果目标对象与源对象有相同字段，并且不为空，则忽略复制
	 *
	 * @param source 源对象
	 * @param target 目标对象
	 */
	public static void copyProperties(Object source, Object target) {
		if (source != null && target != null) {
			List<Field> fieldList = ReflectionKit.getFieldList(target.getClass());
			Set<String> set = new HashSet<>();
			try {
				for (Field field : fieldList) {
					field.setAccessible(true);
					Optional.ofNullable(field.get(target)).ifPresent(e -> set.add(field.getName()));
				}
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
			String[] ignoreProperties = set.toArray(new String[0]);
			BeanUtils.copyProperties(source, target, ignoreProperties);
		}
	}

	/**
	 * 只复制原对象中指定的字段（不管此字段是否为null） 非指定字段忽略
	 *
	 * @param source 原对象
	 * @param target 目标对象
	 * @param includeProperties 指定的字段名
	 */
	public static void copyProperties(Object source, Object target, String... includeProperties) {
		if (source != null && target != null) {
			Set<String> set = Arrays.stream(includeProperties).collect(Collectors.toSet());
			List<Field> fieldList = ReflectionKit.getFieldList(source.getClass());
			String[] ignoreProperties = fieldList.stream().map(Field::getName).filter(s -> !set.contains(s)).toArray(String[]::new);
			// 使用Spring内置工具包（反射实现）
			org.springframework.beans.BeanUtils.copyProperties(source, target, ignoreProperties);
		}
	}

	/**
	 * 只复制原对象中指定的字段 非指定字段忽略
	 *
	 * @param source 原对象
	 * @param target 目标对象
	 * @param includeProperties 指定的字段名
	 */
	public static void copyProperties(Object source, Object target, List<String> includeProperties) {
		copyProperties(source, target, includeProperties.toArray(new String[0]));
	}

	/**
	 * 复制对象属性
	 *
	 * @param source 源对象
	 * @param clazz 目标类对象
	 * @param <T> 目标类泛型
	 * @return 目标对象实例
	 */
	public static <T> T copyProperties(Object source, Class<T> clazz) {
		try {
			T target = clazz.newInstance();
			BeanUtils.copyProperties(source, target);
			return target;
		} catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;
	}
}
